﻿namespace DCHealthCheck.Common {

    #region Usings
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks; 
    #endregion

    internal class HierarchySearcher<T, TProperty> {

        private readonly Func<T, TProperty> idProperty;
        private readonly ILookup<TProperty, T> groupedById;
        private readonly ILookup<TProperty, T> groupedByParent;
        private readonly Func<T, TProperty> parentIdProperty;

        internal HierarchySearcher(IEnumerable<T> items, Func<T, TProperty> idProperty, Func<T, TProperty> parentIdProperty) {
            if (items == null)
                throw new ArgumentNullException("items", "items is null.");
            if (idProperty == null)
                throw new ArgumentNullException("idProperty", "idProperty is null.");
            if (parentIdProperty == null)
                throw new ArgumentNullException("parentIdProperty", "parentIdProperty is null.");

            this.idProperty = idProperty;
            this.parentIdProperty = parentIdProperty;
            this.groupedByParent = items.ToLookup(parentIdProperty);
            this.groupedById = items.ToLookup(idProperty);
        }

        internal IEnumerable<T> GetAllRoots() {
            TProperty parent = default(TProperty);

            return this.groupedByParent[parent];
        }

        internal IEnumerable<T> GetChildren(T parent) {
            if (parent == null) { throw new ArgumentNullException("parent", "parent cannot be null"); }

            TProperty parentId = this.idProperty(parent);

            return this.groupedByParent[parentId];
        }

        internal T GetItemsParent(T item) {
            if (item == null)
                throw new ArgumentNullException("item", "item cannot be null");

            TProperty itemsParentId = this.parentIdProperty(item);

            return this.groupedById[itemsParentId].SingleOrDefault();
        }
    }
}
